﻿using Microsoft.Xna.Framework;

namespace block_explorer
{
    abstract class SceneCamera : Camera
    {
        protected bool mViewMatrixDirty;
        protected bool mProjectionMatrixDirty;

        private int mViewWidth;
        private int mViewHeight;
        private float mFOV;
        private float mNear;
        private float mFar;

        private Vector3 mPosition;

        public Vector3 Position { get { return mPosition; } set { mPosition = value; mViewMatrixDirty = true; } }
        public float Near { get { return mNear; } set { mNear = value; mProjectionMatrixDirty = true; } }
        public float Far { get { return mFar; } set { mFar = value; mProjectionMatrixDirty = true; } }
        public int ViewWidth { get { return mViewWidth; } set { mViewWidth = value; mProjectionMatrixDirty = true; } }
        public int ViewHeight { get { return mViewHeight; } set { mViewHeight = value; mProjectionMatrixDirty = true; } }
        public float AspectRatio { get { return mViewWidth / (float)mViewHeight; } }
        public float FOV { get { return mFOV; } set { mFOV = value; mProjectionMatrixDirty = true; } }

        public override Matrix View
        {
            get
            {
                if (mViewMatrixDirty)
                {
                    UpdateViewMatrix();
                    mViewMatrixDirty = false;
                }
                return base.View;
            }
            set
            {
                base.View = value;
            }
        }

        public override Matrix Projection
        {
            get
            {
                if (mProjectionMatrixDirty)
                {
                    UpdateProjectionMatrix();
                    mProjectionMatrixDirty = false;
                }
                return base.Projection;
            }
            set
            {
                base.Projection = value;
            }
        }

        public SceneCamera(int viewWidth, int viewHeight, float fov, float near, float far)
        {
            mViewMatrixDirty = true;
            mProjectionMatrixDirty = true;

            mViewWidth = viewWidth;
            mViewHeight = viewHeight;
            mFOV = fov;
            mNear = near;
            mFar = far;

            mPosition = Vector3.Zero;
        }

        public virtual void Update(GameTime gameTime)
        {
        }

        protected virtual void UpdateProjectionMatrix()
        {
            Projection = Matrix.CreatePerspectiveFieldOfView(MathHelper.ToRadians(mFOV / 2.0f), AspectRatio, Near, Far);
        }

        protected abstract void UpdateViewMatrix();
    }
}
